package com.ruyuan.homepage.server.controller;

import com.ruyuan.common.model.Response;
import com.ruyuan.common.web.model.WebResponse;
import com.ruyuan.gateway.sdk.facade.RuyuanGatewayFacade;
import com.ruyuan.homepage.server.controller.response.FinanceCostLineChartVO;
import com.ruyuan.homepage.server.controller.response.FinanceIncreaseRateTableVO;
import com.ruyuan.homepage.server.controller.response.FinanceProfitLineChartVO;
import com.ruyuan.homepage.server.service.FinanceStatisticService;
import com.ruyuan.homepage.server.service.model.FinanceIncreaseRateStatisticBO;
import com.ruyuan.homepage.server.service.model.FinanceStatisticBO;
import com.ruyuan.homepage.server.service.request.QueryFinanceIncreaseStatisticsParam;
import com.ruyuan.homepage.server.service.request.QueryFinanceStatisticsParam;
import com.ruyuan.user.api.AuthorityReadFacade;
import com.ruyuan.user.api.OrganizationReadFacade;
import com.ruyuan.user.api.UserReadFacade;
import com.ruyuan.user.api.model.constants.UserAccountInfoExtendKeys;
import com.ruyuan.user.api.model.request.CheckUserAuthorityRequest;
import com.ruyuan.user.api.model.response.AuthorityDTO;
import com.ruyuan.user.api.model.response.JobDetailDTO;
import com.ruyuan.user.api.model.response.OrganizationBaseDTO;
import com.ruyuan.user.api.model.response.UserDetailDTO;
import org.apache.commons.collections.MapUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xx
 */
@Controller
@RequestMapping("/api/homepage/finance")
public class FinanceController {

    private static final String FINANCE_DATA_CODE = "finance_data";

    private static final String FINANCE_DATA_READ_ALL = "finance_data_all_read";

    private static final String FINANCE_DATA_READ_BELONG_ORG = "finance_data_belong_department_read";

    @Autowired
    private FinanceStatisticService financeStatisticService;

    @Autowired
    private RuyuanGatewayFacade ruyuanGatewayFacade;

    @Reference
    private AuthorityReadFacade authorityReadFacade;

    @Reference
    private OrganizationReadFacade organizationReadFacade;

    @Reference
    private UserReadFacade userReadFacade;

    @GetMapping("/costLineChart")
    @ResponseBody
    public WebResponse<List<FinanceCostLineChartVO>> costLineChart() {
        List<FinanceStatisticBO> financeStatisticBOs = getFinanceStatisticBOs();
        List<FinanceCostLineChartVO> costChartList = financeStatisticBOs.stream().map(financeStatisticBO -> {
            FinanceCostLineChartVO financeCostLineChartVO = new FinanceCostLineChartVO();
            financeCostLineChartVO.setDate(financeStatisticBO.getDate());
            financeCostLineChartVO.setOrgName(financeStatisticBO.getOrgName());
            financeCostLineChartVO.setCost(financeStatisticBO.getCost());
            return financeCostLineChartVO;
        }).collect(Collectors.toList());
        return WebResponse.successWithData(costChartList);
    }

    private List<FinanceStatisticBO> getFinanceStatisticBOs() {
        long rootOrgId = Long.parseLong(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID));
        Long userId = ruyuanGatewayFacade.getCurrentUser().getUserId();
        CheckUserAuthorityRequest request = new CheckUserAuthorityRequest();
        request.setUserId(userId);
        request.setAuthResourceCode(FINANCE_DATA_CODE);
        request.setRootOrgId(rootOrgId);
        Response<List<AuthorityDTO>> resp = authorityReadFacade.checkUserAuthority(request);
        if (!resp.isSuccess() || CollectionUtils.isEmpty(resp.getData())) {
            return new ArrayList<>();
        }
        Set<String> userAuthorityCodes = resp.getData().stream().map(AuthorityDTO::getCode).collect(Collectors.toSet());
        QueryFinanceStatisticsParam param = new QueryFinanceStatisticsParam();
        param.setRootOrgId(rootOrgId);
        // 统计5个月的数据
        param.setStatisticMonthCount(5);
        // 根据数据权限范围从大到小，选择最大的一个生效
        if (userAuthorityCodes.contains(FINANCE_DATA_READ_ALL)) {
            // 拥有所有组织查看权限就不做过滤了
        } else if (userAuthorityCodes.contains(FINANCE_DATA_READ_BELONG_ORG)) {
            Set<Long> userAllOrgId = getUserAllOrgId(userId);
            if (CollectionUtils.isEmpty(userAllOrgId)) {
                return new ArrayList<>();
            }
            param.setOrgIds(new ArrayList<>(userAllOrgId));
        } else {
            // 没有数据权限
            return new ArrayList<>();
        }
        return financeStatisticService.queryFinanceStatistics(param);
    }

    private Set<Long> getUserAllOrgId(Long userId) {
        Set<Long> userAllOrgId = new HashSet<>();
        Response<UserDetailDTO> userDetailResp = userReadFacade.queryUserDetail(userId);
        UserDetailDTO userDetailDTO = userDetailResp.getData();
        if (userDetailDTO == null) {
            return userAllOrgId;
        }

        if (userDetailDTO.getMainJob() != null) {
            userAllOrgId.add(userDetailDTO.getMainJob().getOrgId());
        }
        if (MapUtils.isNotEmpty(userDetailDTO.getOtherJobs())) {
            userDetailDTO.getOtherJobs().values().forEach(otherJobs ->
                    userAllOrgId.addAll(otherJobs.stream().map(JobDetailDTO::getOrgId).collect(Collectors.toList())));
        }
        // 还需要查询所有子组织, 有当前组织的数据权限, 相当于也有所有子组织的权限
        List<Long> userAllChildrenOrgIds = userAllOrgId.stream().map(orgId -> {
            Response<List<OrganizationBaseDTO>> allChildrenResp = organizationReadFacade.queryAllChildren(orgId);
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(allChildrenResp.getData())) {
                return allChildrenResp.getData().stream().map(OrganizationBaseDTO::getId).collect(Collectors.toList());
            }
            return new ArrayList<Long>();
        }).flatMap(Collection::stream).collect(Collectors.toList());
        userAllOrgId.addAll(userAllChildrenOrgIds);
        return userAllOrgId;
    }

    @GetMapping("/profitLineChart")
    @ResponseBody
    public WebResponse<List<FinanceProfitLineChartVO>> profitLineChart() {
        List<FinanceStatisticBO> financeStatisticBOs = getFinanceStatisticBOs();
        List<FinanceProfitLineChartVO> profitChartList = financeStatisticBOs.stream().map(financeStatisticBO -> {
            FinanceProfitLineChartVO financeProfitLineChartVO = new FinanceProfitLineChartVO();
            financeProfitLineChartVO.setDate(financeStatisticBO.getDate());
            financeProfitLineChartVO.setOrgName(financeStatisticBO.getOrgName());
            financeProfitLineChartVO.setProfit(financeStatisticBO.getProfit());
            return financeProfitLineChartVO;
        }).collect(Collectors.toList());
        return WebResponse.successWithData(profitChartList);
    }

    @GetMapping("/orgIncreaseTable")
    @ResponseBody
    public WebResponse<List<FinanceIncreaseRateTableVO>> orgIncreaseTable() {
        long rootOrgId = Long.parseLong(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID));
        Long userId = ruyuanGatewayFacade.getCurrentUser().getUserId();
        CheckUserAuthorityRequest checkUserAuthorityRequest = new CheckUserAuthorityRequest();
        checkUserAuthorityRequest.setUserId(userId);
        checkUserAuthorityRequest.setAuthResourceCode(FINANCE_DATA_CODE);
        checkUserAuthorityRequest.setRootOrgId(rootOrgId);
        Response<List<AuthorityDTO>> userAuthorityResp = authorityReadFacade.checkUserAuthority(checkUserAuthorityRequest);
        // 没有权限返回空
        if (org.apache.commons.collections.CollectionUtils.isEmpty(userAuthorityResp.getData())) {
            return WebResponse.successWithData(new ArrayList<>());
        }
        Set<String> userAuthorityCodes = userAuthorityResp.getData().stream().map(AuthorityDTO::getCode).collect(Collectors.toSet());
        QueryFinanceIncreaseStatisticsParam queryFinanceIncreaseStatisticsParam = new QueryFinanceIncreaseStatisticsParam();
        queryFinanceIncreaseStatisticsParam.setRootOrgId(rootOrgId);
        // 数据权限范围从大到小, 选择最大的一个生效
        if (userAuthorityCodes.contains(FINANCE_DATA_READ_ALL)) {
            // 拥有所有组织权限就不对查询参数做进一步的限制了
        } else if (userAuthorityCodes.contains(FINANCE_DATA_READ_BELONG_ORG)) {
            // 如果只有所属组织的权限, 我们要对查询参数做进一步限制
            Set<Long> userAllOrgId = getUserAllOrgId(userId);
            // 用户没加入组织, 返回空结果
            if (org.apache.commons.collections.CollectionUtils.isEmpty(userAllOrgId)) {
                return WebResponse.successWithData(new ArrayList<>());
            }
            queryFinanceIncreaseStatisticsParam.setOrgIds(new ArrayList<>(userAllOrgId));
        } else {
            // 没有数据权限, 返回空
            return WebResponse.successWithData(new ArrayList<>());
        }
        List<FinanceIncreaseRateStatisticBO> financeIncreaseRateStatisticBOS
                = financeStatisticService.queryFinanceIncreaseRateStatistics(queryFinanceIncreaseStatisticsParam);
        List<FinanceIncreaseRateTableVO> financeIncreaseRateTableVOS = financeIncreaseRateStatisticBOS.stream().map(financeIncreaseRateStatisticBO -> {
            FinanceIncreaseRateTableVO financeIncreaseRateTableVO = new FinanceIncreaseRateTableVO();
            BeanUtils.copyProperties(financeIncreaseRateStatisticBO, financeIncreaseRateTableVO);
            financeIncreaseRateTableVO.setProfitIncreaseRate(Optional.ofNullable(financeIncreaseRateStatisticBO.getProfitIncreaseRate())
                    .map(increaseRate -> increaseRate.multiply(new BigDecimal("100")).toPlainString() + "%").orElse("-"));
            return financeIncreaseRateTableVO;
        }).collect(Collectors.toList());
        return WebResponse.successWithData(financeIncreaseRateTableVOS);
    }

}
